#ifndef TRANSACTION_MANAGER_H
#define TRANSACTION_MANAGER_H

#include "../../include/gudb.h"
#include <stdint.h>
#include <stdbool.h>
#include <pthread.h>
#include <time.h>

// Transaction ID type
typedef uint64_t txn_id_t;
typedef uint64_t timestamp_t;

// Special transaction IDs
#define INVALID_TXN_ID      0
#define BOOTSTRAP_TXN_ID    1
#define MAX_TXN_ID          UINT64_MAX

// Transaction states
typedef enum {
    TXN_INVALID = 0,
    TXN_ACTIVE,         // Transaction is running
    TXN_COMMITTED,      // Transaction committed successfully
    TXN_ABORTED,        // Transaction was aborted/rolled back
    TXN_PREPARING,      // Two-phase commit: preparing
    TXN_PREPARED        // Two-phase commit: prepared
} txn_state_t;

// Isolation levels (matching SQL standard)
typedef enum {
    ISOLATION_READ_UNCOMMITTED = 0,  // Dirty reads allowed
    ISOLATION_READ_COMMITTED,        // No dirty reads
    ISOLATION_REPEATABLE_READ,       // No dirty/non-repeatable reads  
    ISOLATION_SERIALIZABLE          // Full isolation
} isolation_level_t;

// Lock types
typedef enum {
    LOCK_SHARED = 0,        // S - Shared lock (read)
    LOCK_EXCLUSIVE,         // X - Exclusive lock (write)
    LOCK_INTENT_SHARED,     // IS - Intent shared
    LOCK_INTENT_EXCLUSIVE,  // IX - Intent exclusive
    LOCK_SHARED_IX,         // SIX - Shared with intent exclusive
    LOCK_UPDATE             // U - Update lock (for SELECT FOR UPDATE)
} lock_mode_t;

// Lock granularity
typedef enum {
    LOCK_TABLE = 0,
    LOCK_PAGE,
    LOCK_TUPLE,
    LOCK_KEY              // Key-range locks for phantom prevention
} lock_granularity_t;

// Forward declarations
typedef struct transaction transaction_t;
typedef struct transaction_manager transaction_manager_t;
typedef struct lock_entry lock_entry_t;
typedef struct lock_table lock_table_t;
typedef struct lock_waiter lock_waiter_t;
typedef struct wait_for_graph wait_for_graph_t;
typedef struct txn_snapshot txn_snapshot_t;
typedef struct version_info version_info_t;
typedef struct undo_log_entry undo_log_entry_t;

// Transaction snapshot for MVCC visibility
struct txn_snapshot {
    txn_id_t xmin;              // Oldest active transaction
    txn_id_t xmax;              // Next transaction ID to be assigned
    txn_id_t my_xid;            // This transaction's ID
    
    // Active transaction set for visibility checks
    txn_id_t* active_xids;      // Array of active transaction IDs
    uint32_t active_count;      // Number of active transactions
    uint32_t active_capacity;   // Capacity of active_xids array
    
    // Snapshot taken time
    timestamp_t snapshot_time;
    
    // Isolation level for this snapshot
    isolation_level_t isolation_level;
};

// Version information for MVCC tuples
struct version_info {
    txn_id_t xmin;              // Transaction that created this version
    txn_id_t xmax;              // Transaction that deleted this version (0 if not deleted)
    uint32_t command_id;        // Command ID within transaction (for statement-level atomicity)
    
    // Visibility information
    bool xmin_committed;        // Whether xmin has been committed
    bool xmax_committed;        // Whether xmax has been committed
    
    // Version chain pointers
    struct version_info* prev_version;  // Previous version
    struct version_info* next_version;  // Next version
};

// Lock entry in the lock table
struct lock_entry {
    txn_id_t holder_xid;        // Transaction holding the lock
    lock_mode_t mode;           // Lock mode
    lock_granularity_t granularity; // Lock granularity
    
    // Lock target identification
    uint32_t table_id;          // Table ID
    uint32_t page_id;           // Page ID (for page locks)
    uint64_t tuple_id;          // Tuple ID (for tuple locks)
    void* key;                  // Key value (for key locks)
    uint32_t key_size;          // Key size
    
    bool granted;               // Whether lock is granted
    struct timespec request_time; // When lock was requested
    
    // Wait queue
    struct lock_entry* next_waiter;
    struct lock_entry* prev_waiter;
    
    // Hash table chain
    struct lock_entry* next_hash;
};

// Lock waiter - represents a transaction waiting for a lock
struct lock_waiter {
    txn_id_t waiter_xid;            // Transaction waiting for lock
    lock_mode_t requested_mode;     // Requested lock mode
    lock_granularity_t granularity; // Lock granularity
    uint32_t table_id;              // Target table ID
    uint32_t page_id;               // Target page ID
    uint64_t tuple_id;              // Target tuple ID
    
    pthread_cond_t wait_cond;       // Condition variable for waiting
    bool granted;                   // Whether lock was granted
    bool cancelled;                 // Whether wait was cancelled
    struct timespec timeout;        // Timeout for lock wait
    
    struct lock_waiter* next;       // Next waiter in queue
    struct lock_waiter* prev;       // Previous waiter in queue
};

// Wait-for graph for deadlock detection
struct wait_for_graph {
    uint32_t max_nodes;             // Maximum number of nodes
    uint32_t node_count;            // Current number of nodes
    txn_id_t* nodes;                // Array of transaction IDs
    bool** edges;                   // Adjacency matrix for wait-for relationships
    pthread_mutex_t mutex;          // Protects the graph
    transaction_manager_t* tm;      // Transaction manager for victim selection
};

// Undo log entry types
typedef enum {
    UNDO_INSERT = 0,                // Undo an insert operation
    UNDO_UPDATE,                    // Undo an update operation
    UNDO_DELETE                     // Undo a delete operation
} undo_operation_type_t;

// Undo log entry for transaction rollback
struct undo_log_entry {
    undo_operation_type_t type;     // Type of operation to undo
    uint32_t table_id;              // Table affected
    uint64_t tuple_id;              // Tuple affected
    void* old_data;                 // Original tuple data (for updates)
    uint32_t data_size;             // Size of old_data
    uint64_t lsn;                   // Log sequence number
    
    struct undo_log_entry* next;    // Next entry in log
};

// Lock table - hash table of lock entries
struct lock_table {
    lock_entry_t** buckets;     // Hash table buckets
    uint32_t bucket_count;      // Number of buckets
    uint32_t lock_count;        // Total number of locks
    
    // Lock waiters
    lock_waiter_t* waiting_head; // Head of waiting queue
    lock_waiter_t* waiting_tail; // Tail of waiting queue
    uint32_t waiter_count;      // Number of waiting transactions
    
    pthread_mutex_t mutex;      // Protects the lock table
    pthread_cond_t wait_cond;   // Condition variable for lock waiters
};

// Transaction structure
struct transaction {
    txn_id_t xid;               // Transaction ID
    txn_state_t state;          // Current state
    isolation_level_t isolation_level; // Isolation level
    
    // Timing information
    timestamp_t start_time;     // When transaction started
    timestamp_t commit_time;    // When transaction committed (0 if not committed)
    timestamp_t abort_time;     // When transaction aborted (0 if not aborted)
    
    // MVCC snapshot
    txn_snapshot_t* snapshot;   // Transaction's view of the database
    
    // Lock management
    lock_entry_t** held_locks;  // Array of locks held by this transaction
    uint32_t held_lock_count;   // Number of locks held
    uint32_t held_lock_capacity; // Capacity of held_locks array
    
    // Transaction log for rollback
    void** undo_log;            // Undo log entries
    uint32_t undo_log_count;    // Number of undo log entries
    uint32_t undo_log_capacity; // Capacity of undo log
    
    // Statistics
    uint64_t tuples_read;       // Tuples read by this transaction
    uint64_t tuples_inserted;   // Tuples inserted
    uint64_t tuples_updated;    // Tuples updated
    uint64_t tuples_deleted;    // Tuples deleted
    uint64_t pages_read;        // Pages read
    uint64_t pages_written;     // Pages written
    
    // Thread information
    pthread_t thread_id;        // Thread executing this transaction
    
    // Connection info
    void* connection;           // Database connection (opaque pointer)
    
    // Next transaction in manager's list
    struct transaction* next;
};

// Transaction manager - central coordinator
struct transaction_manager {
    // Transaction ID management
    txn_id_t next_xid;          // Next transaction ID to assign
    pthread_mutex_t xid_mutex;  // Protects next_xid
    
    // Active transactions
    transaction_t** active_txns; // Hash table of active transactions
    uint32_t active_count;      // Number of active transactions
    uint32_t active_capacity;   // Capacity of active transaction table
    pthread_rwlock_t active_lock; // Protects active transaction table
    
    // Committed transactions (for visibility checks)
    txn_id_t* committed_xids;   // Array of committed transaction IDs
    uint32_t committed_count;   // Number of committed transactions
    uint32_t committed_capacity; // Capacity of committed array
    pthread_mutex_t committed_mutex; // Protects committed array
    
    // Lock management
    lock_table_t* lock_table;   // Global lock table
    wait_for_graph_t* wait_graph; // Wait-for graph for deadlock detection
    
    // Storage engine access
    void* storage_engine;       // Storage engine instance (bw_tree_t*)
    
    // Configuration
    isolation_level_t default_isolation; // Default isolation level
    uint32_t max_active_txns;   // Maximum concurrent transactions
    uint32_t lock_timeout_ms;   // Lock wait timeout in milliseconds
    bool enable_deadlock_detection; // Whether to detect deadlocks
    
    // Statistics
    uint64_t total_txns;        // Total transactions started
    uint64_t committed_txns;    // Total committed transactions
    uint64_t aborted_txns;      // Total aborted transactions
    uint64_t deadlocks_detected; // Number of deadlocks detected
    uint64_t lock_waits;        // Number of lock waits
    uint64_t versions_cleaned;  // Number of MVCC versions cleaned up
    uint64_t dead_tuples_cleaned; // Number of dead tuples found during cleanup
    
    // Cleanup thread
    pthread_t cleanup_thread;   // Background cleanup thread
    bool cleanup_running;       // Whether cleanup thread is running
    pthread_mutex_t cleanup_mutex;
    pthread_cond_t cleanup_cond;
};

// Main transaction manager API
transaction_manager_t* txn_manager_create(void* storage_engine);
void txn_manager_destroy(transaction_manager_t* tm);

// Transaction lifecycle
transaction_t* txn_begin(transaction_manager_t* tm, isolation_level_t isolation);
int txn_commit(transaction_manager_t* tm, transaction_t* txn);
int txn_abort(transaction_manager_t* tm, transaction_t* txn);
int txn_rollback(transaction_manager_t* tm, transaction_t* txn);

// Transaction lookup
transaction_t* txn_get_by_id(transaction_manager_t* tm, txn_id_t xid);
bool txn_is_active(transaction_manager_t* tm, txn_id_t xid);
bool txn_is_committed(transaction_manager_t* tm, txn_id_t xid);
bool txn_is_aborted(transaction_manager_t* tm, txn_id_t xid);

// MVCC visibility functions
txn_snapshot_t* txn_get_snapshot(transaction_manager_t* tm, transaction_t* txn);
bool txn_tuple_visible(txn_snapshot_t* snapshot, version_info_t* version);
bool txn_tuple_visible_for_update(txn_snapshot_t* snapshot, version_info_t* version);

// Lock management
int txn_acquire_lock(transaction_manager_t* tm, transaction_t* txn, 
                    lock_mode_t mode, lock_granularity_t granularity,
                    uint32_t table_id, uint32_t page_id, uint64_t tuple_id);
int txn_release_lock(transaction_manager_t* tm, transaction_t* txn,
                    lock_granularity_t granularity,
                    uint32_t table_id, uint32_t page_id, uint64_t tuple_id);
void txn_release_all_locks(transaction_manager_t* tm, transaction_t* txn);

// Lock compatibility checking
bool locks_compatible(lock_mode_t mode1, lock_mode_t mode2);
bool lock_conflicts(lock_entry_t* existing, lock_mode_t requested_mode);

// Deadlock detection
bool txn_detect_deadlock(transaction_manager_t* tm, transaction_t* txn);
int txn_resolve_deadlock(transaction_manager_t* tm, transaction_t* victim);
wait_for_graph_t* wait_graph_create(transaction_manager_t* tm, uint32_t max_nodes);
void wait_graph_destroy(wait_for_graph_t* graph);
int wait_graph_add_edge(wait_for_graph_t* graph, txn_id_t waiter, txn_id_t holder);
int wait_graph_remove_edge(wait_for_graph_t* graph, txn_id_t waiter, txn_id_t holder);
bool wait_graph_has_cycle(wait_for_graph_t* graph, txn_id_t start_node);
txn_id_t wait_graph_select_victim(wait_for_graph_t* graph, txn_id_t* cycle_nodes, uint32_t cycle_length);

// Enhanced lock management
int txn_acquire_lock_with_wait(transaction_manager_t* tm, transaction_t* txn, 
                              lock_mode_t mode, lock_granularity_t granularity,
                              uint32_t table_id, uint32_t page_id, uint64_t tuple_id,
                              uint32_t timeout_ms);
lock_waiter_t* create_lock_waiter(txn_id_t xid, lock_mode_t mode, lock_granularity_t granularity,
                                 uint32_t table_id, uint32_t page_id, uint64_t tuple_id);
void destroy_lock_waiter(lock_waiter_t* waiter);
int add_lock_waiter(lock_table_t* lock_table, lock_waiter_t* waiter);
int remove_lock_waiter(lock_table_t* lock_table, lock_waiter_t* waiter);
int wake_compatible_waiters(lock_table_t* lock_table, lock_entry_t* released_lock);

// Undo log management
int txn_add_undo_log(transaction_t* txn, undo_operation_type_t type, 
                    uint32_t table_id, uint64_t tuple_id, 
                    void* old_data, uint32_t data_size, uint64_t lsn);
int txn_apply_undo_log(transaction_manager_t* tm, transaction_t* txn);
void txn_clear_undo_log(transaction_t* txn);

// Snapshot management
txn_snapshot_t* snapshot_create(transaction_manager_t* tm, txn_id_t xid, 
                               isolation_level_t isolation);
void snapshot_destroy(txn_snapshot_t* snapshot);
txn_snapshot_t* snapshot_copy(txn_snapshot_t* snapshot);

// Version management
version_info_t* version_create(txn_id_t xmin, uint32_t command_id);
void version_destroy(version_info_t* version);
void version_set_xmax(version_info_t* version, txn_id_t xmax);

// Transaction statistics
void txn_update_stats(transaction_t* txn, uint64_t tuples_read, 
                     uint64_t tuples_written, uint64_t pages_read, uint64_t pages_written);
void txn_print_stats(transaction_t* txn);

// Manager configuration
int txn_manager_set_isolation_level(transaction_manager_t* tm, isolation_level_t level);
int txn_manager_set_lock_timeout(transaction_manager_t* tm, uint32_t timeout_ms);
int txn_manager_set_max_transactions(transaction_manager_t* tm, uint32_t max_txns);

// Cleanup and maintenance
void txn_manager_cleanup_committed(transaction_manager_t* tm);
void txn_manager_vacuum_versions(transaction_manager_t* tm);

// Utility functions
const char* txn_state_to_string(txn_state_t state);
const char* isolation_level_to_string(isolation_level_t level);
const char* lock_mode_to_string(lock_mode_t mode);
const char* lock_granularity_to_string(lock_granularity_t granularity);

// Debugging and monitoring
void txn_manager_print_stats(transaction_manager_t* tm);
void txn_manager_print_active_transactions(transaction_manager_t* tm);
void txn_manager_print_lock_table(transaction_manager_t* tm);

// Internal hash functions
uint32_t hash_lock_key(uint32_t table_id, uint32_t page_id, uint64_t tuple_id);
uint32_t hash_txn_id(txn_id_t xid);

#endif // TRANSACTION_MANAGER_H